require 'rubygems'
require 'net/sftp'
require 'find'

class Installr::SSH::FTP
  def initialize(options={})
    @options = options.dup
    puts "Installr::SSH::FTP module enabled" if @options[:verbose]
  end

  def open(ip_address, username, password)
    @sftp = Net::SFTP.start(ip_address, username, :password => password)
    return 0
    rescue Net::SFTP::StatusException
      return -1
    rescue Net::SSH::AuthenticationFailed
      return -2
  end

  def open_with_cert(ip_address, username, key_data, passphrase)
    @sftp = Net::SFTP.start(ip_address, username, :key_data => [ key_data ], :passphrase => passphrase)
    return 0
    rescue Net::SFTP::StatusException
      return -1
    rescue Net::SSH::AuthenticationFailed
      return -2
  end

  def close
    @sftp.close_channel
  end

  def upload(local_file_path, remote_file_path)
    return -2 unless File.exist?(local_file_path)
    @sftp.upload!(local_file_path, remote_file_path)
    return 0
    rescue Net::SFTP::StatusException
      return -1
  end

  def download(remote_file_path, local_file_path)
    @sftp.download!(remote_file_path, local_file_path)
    return 0
    rescue Net::SFTP::StatusException
      return -1
  end

  def mkdir(remote_directory_path)
    @sftp.mkdir! remote_directory_path
    return 0
    rescue Net::SFTP::StatusException
      return -1
  end

  def upload_all(local_directory_path, remote_directory_path)
    if !File.exist?(local_directory_path) or !File.directory?(local_directory_path)
      return -2 
    end
    file_perm = 0644
    dir_perm = 0755
    if self.mkdir(remote_directory_path) < 0
      return -3
    end

    @sftp.connect do |conn|
      puts 'Checking for files to be uploaded' if @options[:verbose]
      Find.find(local_directory_path) do |file|
        next if File.stat(file).directory?
	local_file = file
	remote_file = remote_directory_path + '/' + local_file.sub(local_directory_path, '')
	begin
	  remote_dir = File.dirname(remote_file)
	  conn.stat!(remote_dir)
	rescue Net::SFTP::StatusException => e 
          raise unless e.code == 2
          conn.mkdir(remote_dir, :permissions => dir_perm)
        end

        begin
          rstat = conn.stat!(remote_file)
	rescue Net::SFTP::StatusException => e
          raise unless e.code == 2
          conn.upload!(local_file, remote_file)
          conn.setstat!(remote_file, :permissions => file_perm)
          next
        end

        if File.stat(local_file).mtime > Time.at(rstat.mtime)
          puts "Copying #{local_file} to #{remote_file}" if @options[:verbose]
          conn.upload!(local_file, remote_file)
        end
      end
    end
    return 0
  end
end
